package chapter1;

import java.util.Iterator;

public class ArrayQueue<T> implements Queue<T> {
    private int head = 0;
    private int last = 0;
    private T[] arr = (T[]) new Object[16];

    public ArrayQueue() {
    }

    public ArrayQueue(int size) {
        arr = (T[]) new Object[size];
    }

    @Override
    public void enqueue(T item) {
        if (item == null) {
            throw new NullPointerException("item can not be null");
        }
        if (isFull()) {
            resize(arr.length * 2);
        }
        arr[last] = item;
        last = (last + 1) % arr.length;

    }

    private boolean isFull() {
        return last == head && arr[head] != null;
    }

    private void resize(int size) {
        T[] temp = (T[]) new Object[size];
        int j = 0;
        for (int i = head; arr[i] != null; i = (i + 1) % arr.length) {
            temp[j++] = arr[i];
            arr[i] = null;
        }
        head = 0;
        last = j;
        arr = temp;
    }

    @Override
    public T dequeue() {
        if (isEmpty()) {
            return null;
        }
        T item = arr[head];
        arr[head] = null;
        head = (head + 1) % arr.length;

        int currentCapacity = 0;
        if (last >= head) {
            currentCapacity = last - head;
        } else {
            currentCapacity = arr.length - (head - last);
        }

        if (currentCapacity == arr.length / 4) {
            resize(arr.length / 2);
        }
        return item;
    }

    @Override
    public boolean isEmpty() {
        return last == head && arr[head] == null;
    }

    @Override
    public int size() {
        return arr.length;
    }

    @Override
    public Iterator<T> iterator() {
        return new ArrayIterator();
    }

    private class ArrayIterator implements Iterator<T> {
        private int start = head;
        @Override
        public boolean hasNext() {
            return arr[start] != null;
        }

        @Override
        public T next() {
            T item = arr[start];
            start = (start + 1) % arr.length;
            return item;
        }
    }
}
